const sw = 20, // 方块的宽度
      sh = 20, // 方块的高度
      tr = 30, // 行数
      td = 30; // 列数
let snake = null, // 蛇实例
    food = null, // 食物实例
    game = null; // 游戏实例

// 方块类
class Square {
    constructor(x,y,classname) {
        this.x = x * sw  // 坐标转为图像像素坐标
        this.y = y * sh  // 坐标转换为图像像素坐标
        this.class = classname
        this.viewContent = document.createElement('div')
        this.viewContent.className = this.class
        this.parent = document.querySelector('#container')
    }
    /* 
     对每一个方块对应的DOM元素样式修饰
    */
    create() {
        this.viewContent.style.position = 'absolute'
        this.viewContent.style.width = sw + 'px'
        this.viewContent.style.height = sh + 'px'
        this.viewContent.style.left = this.x + 'px'
        this.viewContent.style.top = this.y + 'px'
        this.parent.appendChild(this.viewContent) // 加入到容器中
    }
    
    remove() {
        this.parent.removeChild(this.viewContent) // 移除当前DOM元素
    }
}

// 蛇类
class Snake {
    constructor() {
        this.head = null // 蛇头
        this.tail = null // 蛇尾
        this.pos = []   // 存储蛇整个身体和头部所在小方块的坐标
        this.directionNum = {
            left: {
                x: -1,
                y: 0
            },
            right: {
                x: 1,
                y: 0
            },
            up: {
                x: 0,
                y: -1
            },
            down: {
                x: 0,
                y: 1
            }
        }
    }

    init() {
        // 初始化蛇头
        let snakehead = new Square(2,0,'snakeHead') 
        snakehead.create()
        this.head = snakehead // 存储蛇头信息
        this.pos.push([2,0]) // 存储了蛇头位置

        let snakebody1 = new Square(1,0,'snakeBody')
        snakebody1.create()
        this.pos.push([1,0])
        
        let snakebody2 = new Square(0,0,'snakeTail')
        snakebody2.create()
        this.pos.push([0,0])
        this.tail = snakebody2 // 存储蛇尾

        // 形成一个链表关系
        snakehead.last = null
        snakehead.next = snakebody1

        snakebody1.last = snakehead
        snakebody1.next = snakebody2

        snakebody2.last = snakebody1
        snakebody2.next = null

        // 添加一条属性，表示蛇走的方向
        this.direction = this.directionNum.right
    }


    // 这个方法是描述根据蛇头的下一个位置对应的坐标，判断蛇的状态的改变
    getNextPos() {
        // 蛇头要移动到下一步的方块坐标（物理坐标）
        let nextPos = [
            this.head.x / sw + this.direction.x,
            this.head.y / sh + this.direction.y
        ]

        // 四种情况，1. 撞到自己 2.撞墙 3.吃到一个苹果，4，空地可以走
        // 1.撞到自己
        let killme = false
        this.pos.forEach((item) => {
            // 自己撞到自己了
            if (item[0] === nextPos[0] && item[1] === nextPos[1]) {
                killme = true
            }
        })
        if (killme) {
            // 结束游戏，显示分数，提醒再接再厉
        }

        // 2.撞墙
        if (nextPos[0] < 0 || nextPos[0] > 29 || nextPos[1] < 0 || nextPos[1] > 29) {
            // 结束游戏了
        }

        // 3.吃到一个苹果
        if (food.pos[0] === nextPos[0] && food.pos[1] === nextPos[1]) {
            // 增大
            console.log('11111')
            this.eat(nextPos)
            return 
            
        }

        // 4.空地可以走
        this.move(nextPos,false)
    }

    // 蛇移动的事件
    move(nextPost,state) {
        let nextPos = nextPost
        // 把蛇头改为身体，再创建一个蛇头
        let newBody = new Square(this.head.x / sw,this.head.y / sh,'snakeBody')

        // 更新身体节点
        newBody.next = this.head.next
        newBody.next.last = newBody
        newBody.last = null
        newBody.create() // 加入容器
        // 去除头部
        this.head.remove()

        // 在下一个位置新建一个节点
        let newHead = new Square(nextPos[0],nextPos[1],'snakeHead')
        // 根据移动的方向，修改蛇头方向
        if (this.direction === this.directionNum.left) {
            newHead.viewContent.style.background = 'url(./img/left.png)'
        } else if (this.direction === this.directionNum.right) {
            newHead.viewContent.style.background = 'url(./img/right.png)'
        } else if (this.direction === this.directionNum.up) {
            newHead.viewContent.style.background = 'url(./img/up.png)'
        } else {
            newHead.viewContent.style.background = 'url(./img/down.png)'
        }
        newHead.last = null
        newHead.next = newBody
        newBody.last = newHead
        newHead.create() // 加入容器

        // 蛇身上的坐标进行一个整体更新
        this.pos.unshift([this.head.x / sw + this.direction.x, this.head.y / sh + this.direction.y]);
        this.head = newHead; //把this.head的信息更新

        // 删除蛇尾 通过判断是否吃food，如果吃了food，就不删除，若是没有吃，就删除

        if (!state) { //如果format 的值为false  表示需要删除（除了吃之外的操作）
            this.tail.remove();
            // 更新链表
            this.tail = this.tail.last;
            this.tail.next = null;

            // 更新蛇身坐标数组
            this.pos.pop();
        }
    }
    // 蛇吃食物的事件
    eat(nextPos) {
        food.init()
        this.move(nextPos,true)
    }
}
// 蛇的实例对象
snake = new Snake()
snake.init()

// 食物
class Food {
    // 初始化坐标
    init() {
        let x = null, y = null
        let status = true // 判断是否还需重新分配一个坐标

        while(status) {
            x = Math.round(Math.random() * 29)
            y = Math.round(Math.random() * 29)
            snake.pos.forEach(item => {
                if (item[0] !== x && item[1] !== y) {
                    status = false // 重新分配
                }
            })       
        }
        
        this.food = new Square(x,y,'food')
        this.pos = [x,y] // 存储下来与蛇头作比较
        
        // 如果不存在就创建，存在就移动位置
        let foodExist = document.querySelector('.food')
        if (foodExist) {
            foodExist.style.left = x * sw  + 'px'
            foodExist.style.top = x * sh + 'px'
        } else {
            this.food.create()
        }
    }
}

food = new Food()
food.init()

let id = null
document.addEventListener('keydown',function(e){
    clearInterval(id)
    if (e.key === 'd') {
        id = setInterval(()=>{
            snake.direction = snake.directionNum.right
            snake.getNextPos()
        },200)
       
    } else if (e.key === 's') {
        // 更改一下蛇的方向
        id = setInterval(()=>{
            snake.direction = snake.directionNum.down
            snake.getNextPos()
        },200)
             
       
    } else if (e.key === 'w') {
        id = setInterval(()=>{
             snake.direction = snake.directionNum.up
            snake.getNextPos()
        
        },200)
           
    } else if (e.key === 'a') {
        id = setInterval(()=>{
            snake.direction = snake.directionNum.left
            snake.getNextPos()
        
        },200)
            
    }
})